/* udp-broadcast-server.c:
 * udp broadcast server example 
 * Example Stock Index Broadcast:
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

extern int mkaddr(
	void *addr,
	int *addrlen,
	char *str_addr,
	char *protocol);

#define MAXQ 4

static struct {
	char *index;
	int start;
	int volit;
	int current;
} quotes[] = {
	{ "DJIA", 1030330, 375 },
	{ "NASDAQ", 276175, 125 },
	{ "S&P 500", 128331, 50 },
	{ "TSE 300", 689572, 75 },
};

/*
 * Initialize:
 */
static void initialize(void) 
{
	short x;
	time_t td;

	/*
	 * Seed the random number generator:
	 */
	time(&td);
	srand((int)td);

	for ( x=0; x < MAXQ; ++x )
		quotes[x].current = quotes[x].start;
}

/*
 * Randomly change one index quotation:
 */
static void
gen_quote(void) {
	short x;    /* Index */
	short v;    /* Volatility of index */
	short h;    /* Half of v */
	short r;    /* Random change */

	x = rand() % MAXQ;
	v = quotes[x].volit;
	h = (v / 2) - 2;
	r = rand() % v;
	if ( r < h )
		r = -r;
	quotes[x].current += r;
}

/*
 * This function reports the error and
 * exits back to the shell:
 */
static void
displayError(const char *on_what) {
	fputs(strerror(errno),stderr);
	fputs(": ",stderr);
	fputs(on_what,stderr);
	fputc('\n',stderr);
	exit(1);
}

int main(int argc,char **argv) 
{
	short x;    /* index of Stock Indexes */
	double I0;  /* Initial index value */
	double I;   /* Index value */
	char bcbuf[512], *bp;/* Buffer and ptr */
	int z;      /* Status return code */
	int s;      /* Socket */
	int len_srvr;               /* length */
	int len_bc;                 /* length */

	static char *sv_addr = "192.168.1.119:2312", *bc_addr = "192.168.1.255:9097";
	struct sockaddr_in adr_srvr;
	struct sockaddr_in adr_bc;
	if ( argc > 2 )
		sv_addr = argv[2];
	if ( argc > 1 )
		bc_addr = argv[1];

	len_srvr = sizeof adr_srvr;
	z = mkaddr(&adr_srvr, &len_srvr, sv_addr, "udp");
	if ( z == -1 )
		displayError("Bad server address");

	len_bc = sizeof adr_bc;
	z = mkaddr(&adr_bc, &len_bc, bc_addr, "udp");
	if ( z == -1 )
		displayError("Bad broadcast address");

	s = socket(AF_INET,SOCK_DGRAM,0);
	if ( s == -1 )
		displayError("socket()");

	static int so_broadcast = 1;
	z = setsockopt(s, SOL_SOCKET, SO_BROADCAST, 
		&so_broadcast, sizeof so_broadcast);
	if ( z == -1 )
		displayError("setsockopt(SO_BROADCAST)");

	struct ifreq irq;
	strcpy(irq.ifr_name, "wlp2s0");
	ioctl(s, SIOCGIFFLAGS, &irq);

	if(irq.ifr_flags & IFF_BROADCAST == 0) {
		printf("device:%s do not support broadcast\n", irq.ifr_name);
		exit(-1);
	}

	printf("server:%s,port:%d\n",inet_ntoa(adr_srvr.sin_addr), ntohs(adr_srvr.sin_port));
	z = bind(s, (struct sockaddr *)&adr_srvr, len_srvr);
	if ( z == -1 )
		displayError("bind()");

	initialize();

	for (;;) {
		/*
		 * Update one quote in the list:
		 */
		gen_quote();

		/*
		 * Form a packet to send out:
		 */
		bp = bcbuf;
		for ( x=0; x<MAXQ; ++x ) {
			I0 = quotes[x].start / 100.0;
			I = quotes[x].current / 100.0;
			sprintf(bp,
				"%-7.7s %8.2f %+.2f\n",
				quotes[x].index,
				I,
				I - I0);
			bp += strlen(bp);
		}

		/*
		 * Broadcast the updated info:
		 */
		printf("broad cast:%s, port:%d\n",inet_ntoa(adr_bc.sin_addr), ntohs(adr_bc.sin_port));
		z = sendto(s, bcbuf, strlen(bcbuf), 0, 
			(struct sockaddr *)&adr_bc, len_bc); 
		if ( z == -1 ) {
			printf("sendto\n");
			printf("%s\n", strerror(errno));
			exit(-1);
		}
		sleep(1);
	}

	return 0;
}
